﻿#region Copyright (c) 2010 R. Uittenbosch
/*
* Copyright (C) 2010 R. Uittenbosch
* 
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 
* associated documentation files (the "Software"), to deal in the Software without restriction, including 
* without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 
* copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the 
* following conditions:
* 
* The above copyright notice and this permission notice shall be included in all copies or substantial 
* portions of the Software.
* 
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT 
* LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO 
* EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 
* IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 
* USE OR OTHER DEALINGS IN THE SOFTWARE.
*/
#endregion

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using TouchUI;
using System.Drawing;
using TouchUI.System.Mobile.Mvc;
using LinkedService.Mobile.ServiceEntities;
using LinkedIn.Mobile.Properties;
using System.Windows.Forms;
using LinkedService.Mobile;

namespace LinkedIn.Mobile
{
 
  /// <summary>
  /// The scrollpanel for the users profile
  /// </summary>
  class ProfileDetailScrollPanel: ScrollPanel
  {
    #region Private variables
    private Bitmap bmpOffscreen;
    private int currentImage;
    private int animationOffset;
    private int animationLeft;
    private Person _person;
    private Bitmap _image;
    private Color boxBackground = Color.White;
    private Color boxBorder = Color.DarkGray;
    private Color profileBackground = Color.White;
    private Bitmap _distanceImage;
    private bool _firstTimeDrawing = true;

    #endregion

    #region Public static properties
    public static int ImageSize = 50 * Common.Instance.ScreenFactor;
    public static int Spacing = 2 * Common.Instance.ScreenFactor;
    public static int HSpacing = 10 * Common.Instance.ScreenFactor;
    #endregion

    #region Constructor
    public ProfileDetailScrollPanel()
    {
        // Init the screen
        ScreenFactor  = Common.Instance.ScreenFactor;
        Rectangle     = Common.Instance.ClientRectangle;
        // Default Scrollheight
        ScrollHeight  = 600 * ScreenFactor;
    }

    #endregion

    #region Public Properties

    /// <summary>
    /// Accept the new user.
    /// </summary>
    public Person User 
    {
      set
      {
        _person = value;

        // Clear the offscreen image
        if (bmpOffscreen != null)
          bmpOffscreen.Dispose();
        bmpOffscreen = null;
        _firstTimeDrawing = true;
        ScrollTop = 0;
        // If there is a picture available, download it.
        if (!string.IsNullOrEmpty(_person.PictureUrl))
          _image = ProfileImageLoader.LoadPicture(_person.PictureUrl);
        else
          _image = Resources.icon_no_photo_40x40;
        // Determine distance
        _distanceImage = null;
        if (_person.Distance == 1)
          _distanceImage = Resources.icon_degree_1;
        if (_person.Distance == 2)
          _distanceImage = Resources.icon_degree_2;
        if (_person.Distance == 3)
          _distanceImage = Resources.icon_degree_3;
        if (_person.Id == ApplicationManager.Configuration.GetItem<string>("CurrentUser"))
          _distanceImage = Resources.icon_you;
      }
    }
    #endregion

    #region ProfileDrawing
    //
    //   //////   Name
    //   //  //
    //   //////   HeadLine
    //
    //   Specialties
    // 
    //   Summary
    //
    //   Positions
    //
    //
    //
    /// <summary>
    /// Draw the profile offscreen
    /// </summary>
    private void DrawProfile(Graphics g)
    {
      bool limitedProfile = false;
      bool ok = false;
      int minheight = 650;
      do
      {
        try
        {
          bmpOffscreen = new Bitmap(Common.Instance.PaintBitmap.Width, ScrollHeight);
          ok = true;
        }
        catch (OutOfMemoryException e)
        {
          // Too large?
          minheight -= 50;
          // Reset scrollheigt and limit the profile
          ScrollHeight = minheight * ScreenFactor;
          limitedProfile = true;
          ok = true;
        }
      } while (!ok);

      //Offscreen graphics
      Graphics gx  = Graphics.FromImage(bmpOffscreen);
      gx.Clear(profileBackground);

      if (_image != null)
      {
        // Picture
        gx.DrawImage(_image, new Rectangle(Rectangle.Left,
                                          Rectangle.Top,
                                          ImageSize,
                                          ImageSize),
                new Rectangle(0, 0, _image.Width, _image.Height), GraphicsUnit.Pixel);
      }
      int maxstringwidth = Rectangle.Width - HSpacing - ImageSize - (16 * ScreenFactor);
      int left = 0;
      int top = 0;
      // Name

      if (_distanceImage != null)
        gx.DrawImage(_distanceImage, Rectangle.Width  - (16 * ScreenFactor) - _distanceImage.Width, top);


      top = DrawString(gx, top, ImageSize, _person.Name, Common.Instance.SubFont, Common.Instance.FontBrush) + Spacing;


      // Headline
      if (!string.IsNullOrEmpty(_person.Headline))
      {
        top = DrawString(gx, top + Spacing, ImageSize, _person.Headline, Common.Instance.SubFont, Common.Instance.FontBrush);
      }

      if (_distanceImage == null)
        top = DrawString(gx, top, left, Strings.OutOfNetwork, Common.Instance.SmallFont, Common.Instance.GrayBrush, new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Far });

            
      if (top < ImageSize)
        top = ImageSize + HSpacing;        

      // Status
      if (!string.IsNullOrEmpty(_person.CurrentStatus))
      {
        top = DrawString(gx, top, left, Strings.ProfileStatus, Common.Instance.SmallFont, Common.Instance.HeadBrush, new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Far });

        top = DrawBoxedString(gx, top, 0, _person.CurrentStatus, Common.Instance.SmallFont);       
      }

      // Specialties
      if (!string.IsNullOrEmpty(_person.Specialties))
      {
        top = DrawString(gx, top, left, Strings.ProfileSpecialties, Common.Instance.SmallFont, Common.Instance.HeadBrush, new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Far });

        top = DrawBoxedString(gx, top, 0, _person.Specialties, Common.Instance.SmallFont);
      }

      // Summary
      if (!string.IsNullOrEmpty(_person.Summary))
      {
        top = DrawString(gx, top, left, Strings.ProfileSummary, Common.Instance.SmallFont, Common.Instance.HeadBrush, new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Far });

        top = DrawBoxedString(gx, top, 0, _person.Summary, Common.Instance.SmallFont);
      }

      // Associations
      if (!string.IsNullOrEmpty(_person.Associations) && !limitedProfile)
      {
        top = DrawString(gx, top, left, Strings.Associations, Common.Instance.SmallFont, Common.Instance.HeadBrush, new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Far });

        top = DrawBoxedString(gx, top, 0, _person.Associations, Common.Instance.SmallFont);
      }
      
      // Honors
      if (!string.IsNullOrEmpty(_person.Honors) && !limitedProfile)
      {
        top = DrawString(gx, top, left, Strings.Honors, Common.Instance.SmallFont, Common.Instance.HeadBrush, new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Far });

        top = DrawBoxedString(gx, top, 0, _person.Honors, Common.Instance.SmallFont);
      }
      // Positions
      if (_person.Positions != null)
      {

        top = DrawString(gx, top, left, Strings.ProfileExperience, Common.Instance.SmallFont, Common.Instance.HeadBrush, new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Far });
        foreach (Position p in _person.Positions)
        {
          int ctop = top;
          // Paint everything, first to be able to know the size of the box,
          // than paint again with the correct background
          top = DrawPosition(gx, ctop, left, p);
          // Make the background gray
          DrawBox(gx, ctop, left, top - ctop);
          // Draw again ontop of the box
          top = DrawPosition(gx, ctop, left, p);
          top += HSpacing;
        }
        
      }
      if (_person.Educations != null && !limitedProfile)
      {
        top = DrawString(gx, top, left, Strings.ProfileEducation, Common.Instance.SmallFont, Common.Instance.HeadBrush, new StringFormat() { Alignment = StringAlignment.Far, LineAlignment = StringAlignment.Far});
        foreach (Education edu in _person.Educations)
        {
          int ctop = top;
          // Paint everything, first to be able to know the size of the box,
          // than paint again with the correct background
          top = DrawEducation(gx, ctop, left, edu);
          // Make the background gray
          DrawBox(gx, ctop, left, top - ctop);
          // Draw again ontop of the box
          top = DrawEducation(gx, ctop, left, edu);
          top += HSpacing;
        }
      }
      
      ScrollHeight = top;
      // Draw the image.
      g.DrawImage(
        bmpOffscreen, 
        0, 
        ScrollTop, 
        new Rectangle(0, 0, bmpOffscreen.Width, ScrollHeight), 
        GraphicsUnit.Pixel);

      if (_firstTimeDrawing)
      {
        // We clean the image again, so it will be drawn next time again
        // with the correct scrollheigth.
        bmpOffscreen.Dispose();
        bmpOffscreen = null;

        // Next time do not dispose.
        _firstTimeDrawing = false;
      }

    }

    private int DrawEducation(Graphics gx, int top, int left, Education edu)
    {
      string date = string.Empty;
      if (edu.StartDate != null)
      {
        string startMonth = edu.StartDate.Month != 0 ? System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(edu.StartDate.Month) : string.Empty;
        date = string.Format("{0} - {1}", edu.StartDate != null ? startMonth + " " + edu.StartDate.Year : "       ",
                                          edu.IsCurrent ? Strings.ProfilePresent : (edu.EndDate.Month != 0 ? System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(edu.EndDate.Month) : string.Empty) + " " + edu.EndDate.Year);
      }
      if (!string.IsNullOrEmpty(edu.SchoolName))
        top = DrawString(gx, top, left, edu.SchoolName, Common.Instance.SubFont, Common.Instance.FontBrush);

      if (!string.IsNullOrEmpty(edu.FieldOfStudy))
        top = DrawString(gx, top, left, edu.FieldOfStudy, Common.Instance.SmallFont, Common.Instance.BlueBrush);

      // date
      top = DrawString(gx, top, left, date, Common.Instance.SmallFont, Common.Instance.GrayBrush);
      if (!string.IsNullOrEmpty(edu.Degree))
        top = DrawString(gx, top, left, edu.Degree, Common.Instance.SmallFont, Common.Instance.FontBrush);
      if (!string.IsNullOrEmpty(edu.Notes))
        top = DrawString(gx, top, left, edu.Notes, Common.Instance.SmallFont, Common.Instance.FontBrush);
      if (!string.IsNullOrEmpty(edu.Activities))
        top = DrawString(gx, top, left, edu.Activities, Common.Instance.SmallFont, Common.Instance.FontBrush);

      return top;
    }

    private int DrawPosition(Graphics gx, int top, int left, Position p)
    {
      string date = string.Empty;
      if (p.StartDate != null)
      {
        string startMonth = p.StartDate.Month != 0 ? System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(p.StartDate.Month) : string.Empty;
        date = string.Format("{0} - {1}", p.StartDate != null ? startMonth + " " + p.StartDate.Year : "       ",
                                          p.IsCurrent ? Strings.ProfilePresent : (p.EndDate.Month != 0 ? System.Globalization.CultureInfo.CurrentCulture.DateTimeFormat.GetMonthName(p.EndDate.Month) : string.Empty) + " " + p.EndDate.Year);
      }
      if (p.Company != null && !string.IsNullOrEmpty(p.Title))
      {
        top = DrawString(gx, top, left, string.Format("{0}", p.Title), Common.Instance.SubFont, Common.Instance.FontBrush);
        top = DrawString(gx, top, left, p.Company.Name, Common.Instance.SubFont, Common.Instance.BlueBrush);
      }
      else
      {
        // Company
        if (p.Company != null)
          top = DrawString(gx, top, left, p.Company.Name, Common.Instance.SubFont, Common.Instance.FontBrush);

        // Title
        if (!string.IsNullOrEmpty(p.Title))
          top = DrawString(gx, top, left, p.Title, Common.Instance.SmallFont, Common.Instance.FontBrush);
      }
      top = DrawString(gx, top, left, date, Common.Instance.SmallFont, Common.Instance.GrayBrush);
      // Summary
      if (!string.IsNullOrEmpty(p.Summary))
        top = DrawString(gx, top, left, p.Summary, Common.Instance.SmallFont, Common.Instance.FontBrush);

      return top;
    }

    #endregion

    #region Drawing

    public override void Resize(Rectangle r)
    {
      base.Resize(r);
      Rectangle = r;
      _firstTimeDrawing = true;
      if (bmpOffscreen != null)
        bmpOffscreen.Dispose();
      bmpOffscreen = null;
    }

    /// <summary>
    /// Paint the profile offscreen and afterwards paint the image using the scrollTop.
    /// </summary>
    /// <param name="g"></param>
    public override void Paint(Graphics g)
    {
      // Always paint the base, this will make sure we can scroll
      base.Paint(g);
      // Did we already paint?
      if (bmpOffscreen == null)
        DrawProfile(g);
      else
        // Draw the profile on screen
        g.DrawImage(bmpOffscreen, 0, ScrollTop, new Rectangle(0,0,bmpOffscreen.Width, ScrollHeight), GraphicsUnit.Pixel);
     
    }

    /// <summary>
    /// Draw a nice box around the different blocks of data
    /// </summary>
    /// <param name="g"></param>
    /// <param name="top"></param>
    /// <param name="left"></param>
    /// <param name="s"></param>
    /// <param name="f"></param>
    private int DrawBoxedString(Graphics g, int top, int left, string s, Font f)
    {
      RectangleF drawRec = new RectangleF(Rectangle.Left + Spacing + left,
                                              Rectangle.Top  + top,
                                              Rectangle.Width - (Spacing * 2),
                                              ScrollHeight);

      RectangleF drawRecs = new RectangleF(Rectangle.Left + HSpacing + left,
                                    Rectangle.Top  + top,
                                    Rectangle.Width - (16 * ScreenFactor) - left,
                                    ScrollHeight);

      Size size  = g.MeasureString(s, f, drawRecs);

      if (size.Height < 24)
        size.Height = 30;

      g.DrawRoundedRectangle(new Pen(boxBorder) { DashStyle = System.Drawing.Drawing2D.DashStyle.Dash }, boxBackground, new Rectangle((int)drawRec.Left, (int)drawRec.Top, (int)drawRec.Width, size.Height), new Size(24, 24));

      g.DrawString(s, f, Common.Instance.FontBrush, drawRecs, new StringFormat());
      // Where should we draw next
      top += (size.Height + HSpacing);

      return top;
    }

    private void DrawBox(Graphics g, int top, int left, int height)
    {
      RectangleF drawRec = new RectangleF(Rectangle.Left + Spacing + left,
                                              Rectangle.Top  + top,
                                              Rectangle.Width - (Spacing * 2),
                                              ScrollHeight);

      int bottom = height - Spacing;
      g.DrawRoundedRectangle(new Pen(boxBorder) {  DashStyle = System.Drawing.Drawing2D.DashStyle.Dash}, boxBackground, new Rectangle((int)drawRec.Left, (int)drawRec.Top, (int)drawRec.Width, bottom), new Size(24, 24));

    }

    private int DrawString(Graphics g, int top, int left, string s, Font f, Brush fontBrush)
    {
      return DrawString(g, top, left, s, f, fontBrush, new StringFormat());
    }

    private int DrawString(Graphics g, int top, int left, string s, Font f, Brush fontBrush, StringFormat format)
    {
      Size size;
      RectangleF drawRec = new RectangleF(Rectangle.Left + HSpacing + left,
                                              Rectangle.Top  + top,
                                              Rectangle.Width - (16 * ScreenFactor) - left,
                                              ScrollHeight);
      size = g.MeasureString(s, f, drawRec);
      drawRec.Height = size.Height;

      g.DrawString(s,
                              f,
                              fontBrush,
                              drawRec,
                              format);
      // Where should we draw next
      top += (size.Height + Spacing);

      return top;
    }

    #endregion

    #region Mouse/Key events
    /// <summary>
    /// Handle MouseUp event
    /// </summary>
    /// <param name="p"></param>
    public override void MouseUp(Point p)
    {
        base.MouseUp(p);
    }

    public override void KeyUp(KeyEventArgs e)
    {
        base.KeyUp(e);

        if(e.KeyCode == Keys.Up)
        {
            ScrollTop += Rectangle.Height / 4;
            if(ScrollTop > 0)
                ScrollTop = 0;
        }
        else if(e.KeyCode == Keys.Down)
        {
            ScrollTop -= Rectangle.Height / 4;
            if(ScrollTop < Rectangle.Height - Rectangle.Top - ScrollHeight)
                ScrollTop = Rectangle.Height - Rectangle.Top - ScrollHeight;
        }
        else if(e.KeyCode == Keys.Right && currentImage < 1)
        {
            animationOffset = Rectangle.Width / 4;
            animationLeft = Rectangle.Width;
            currentImage++;
        }
        else if(e.KeyCode == Keys.Left && currentImage > 0)
        {
            animationOffset = -Rectangle.Width / 4;
            animationLeft = -Rectangle.Width;
            currentImage--;
        }
        e.Handled = true;
    }
    #endregion
  }
}
